/**
 * @Author: 490912587@qq.com
 * @Description:
 * @File:  AuthMiddleware
 * @Version: 1.0.0
 * @Date: 2021/11/2 10:57
 * AuthMiddleware是我们用来检查令牌是否有效的中间件。如果返回401状态无效，则返回给客户。
 * TokenHandler是我们获取用户名和密码的处理程序，如果有效，则返回用于将来请求的令牌。
 */
package middleware

import (
	"net/http"
	"server/database/model"
	"server/tool"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
)

type Claims struct {
	UserID uint
	jwt.StandardClaims
}

func GetCaptchaHandler(ctx *gin.Context) {
	captcha := tool.GetCaptcha()
	if (captcha != tool.Captcha{}) {
		ctx.JSON(http.StatusOK, gin.H{"code": 200, "msg": "验证码生成成功！", "data": captcha})
	} else {
		ctx.JSON(http.StatusOK, gin.H{"code": 201, "msg": "验证码生成失败！"})
	}
}

// =====================登录相关===========================
// PC后台登录
func PasswordHandler(ctx *gin.Context) {
	account := ctx.PostForm("account")
	password := ctx.PostForm("password")
	dots := ctx.PostForm("dots")
	key := ctx.PostForm("captcha_key")
	_, errCapt := tool.Check(key, dots)
	var user model.User
	param := model.User{
		Account:  account,
		Password: password,
	}
	result, err := user.GetByPass(param)
	if errCapt != nil {
		ctx.JSON(http.StatusOK, gin.H{"code": 401, "msg": "人机验证失败！"})
		ctx.Abort()
		return
	}
	if err == nil {
		expire := tool.Config().Jwt.Expire
		expireTime := time.Now().Add(time.Duration(expire) * time.Second)
		claims := &Claims{
			UserID: result.ID,
			StandardClaims: jwt.StandardClaims{
				ExpiresAt: expireTime.Unix(), //过期时间
				IssuedAt:  time.Now().Unix(),
				Issuer:    "127.0.0.1",  // 签名颁发者
				Subject:   "user token", //签名主题
			},
		}
		token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
		tokenStr, errToken := token.SignedString([]byte(tool.Config().Jwt.AppKey))
		//根据用户的角色ID获取角色多个授权标识
		var rolePermission model.RolePermission
		permission, errRole := rolePermission.GetPermissionsByRoleID(uint(result.RoleId))
		var permissions []string
		for _, auth := range permission {
			permissions = append(permissions, auth.Permission)
		}
		if errToken != nil && errRole != nil {
			ctx.JSON(http.StatusOK, gin.H{"code": 401, "msg": "获取用户信息失败！"})
			ctx.Abort()
			return
		}
		redis, errRedis := tool.Conn()
		if errRedis == nil {
			tool.SetValue(redis, string(result.ID), tokenStr)
		}
		config := tool.Config()
		ctx.JSON(http.StatusOK,
			gin.H{
				"code":  200,
				"msg":   "获取Token成功！",
				"token": tokenStr,
				"userinfo": gin.H{
					"id":          result.ID,
					"account":     result.Account,
					"nickname":    result.NickName,
					"avatar":      config.Os.DoMain + result.Avatar,
					"permissions": permissions,
				},
			})
	} else {
		ctx.JSON(http.StatusOK, gin.H{"code": 401, "msg": "账号密码有误/账号冻结，请联系管理员！"})
	}
}

// PC后台退出
func PasswordLoginOut(ctx *gin.Context) {
	tokenString := ctx.GetHeader("Authorization")
	if tokenString == "" {
		ctx.JSON(http.StatusOK, gin.H{"code": 201, "msg": "参数非法！"})
	} else {
		claims, err := ParseToken(tokenString)
		if err != nil {
			ctx.JSON(http.StatusOK, gin.H{"code": 201, "msg": "操作非法！"})
		} else {
			redis, errRedis := tool.Conn()
			if errRedis != nil {
				ctx.JSON(http.StatusOK, gin.H{"code": 201, "msg": "退出失败！"})
			} else {
				count, errDel := tool.DelCache(redis, string(claims.UserID))
				if errDel == nil && count > 0 {
					ctx.JSON(http.StatusOK, gin.H{"code": 200, "msg": "安全退出成功！"})
				} else {
					ctx.JSON(http.StatusOK, gin.H{"code": 201, "msg": "退出失败！"})
				}
			}
		}
	}
}

// 短信验证码登录
func PhoneCodeHandler(ctx *gin.Context) {
}

// 微信小程序登录
func WxAppletHandler(ctx *gin.Context) {
}

// =====================登录相关===========================
// =====================Token获取用户信息===========================
func GetUserInfo(ctx *gin.Context) {
	tokenString := ctx.GetHeader("Authorization")
	if tokenString == "" {
		ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "Authorization Failed！"})
	} else {
		UserInfo, err := ParseToken(tokenString)
		if err != nil {
			ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": err.Error()})
		} else {
			var user model.User
			var role model.Role
			result, err := user.GetOne(UserInfo.UserID)
			permission, errRole := role.GetOne(uint(result.RoleId))
			if err == nil && errRole == nil {
				var permissions []string
				for _, auth := range permission.Permission {
					permissions = append(permissions, auth.Permission)
				}
				ctx.JSON(http.StatusOK, gin.H{"code": 200, "msg": "获取用户信息成功！", "userinfo": result, "permissions": permissions})
			} else {
				ctx.JSON(http.StatusOK, gin.H{"code": 201, "msg": "获取用户信息失败！"})
			}
		}
	}
}

// =====================Token获取用户信息===========================
// =====================授权相关===========================
func AuthMiddleware(ctx *gin.Context) {
	tokenString := ctx.GetHeader("Authorization")
	if tokenString == "" {
		ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "Authorization Failed！"})
		ctx.Abort()
		return
	}
	claims, err := ParseToken(tokenString)
	if err != nil {
		ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": err.Error()})
		ctx.Abort()
		return
	} else {
		redis, errRedis := tool.Conn()
		if errRedis != nil {
			ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": errRedis.Error()})
			ctx.Abort()
			return
		}
		token, errToken := tool.GetValue(redis, string(claims.UserID))
		if errToken != nil && len(token) == 0 {
			ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": errToken.Error()})
			ctx.Abort()
			return
		}
	}
}
func ParseToken(tokenString string) (*Claims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &Claims{},
		func(token *jwt.Token) (i interface{}, err error) {
			return []byte(tool.Config().Jwt.AppKey), nil
		})
	if claims, ok := token.Claims.(*Claims); ok && token.Valid {
		return claims, nil
	} else {
		return nil, err
	}
}

// =====================授权相关===========================
